import { FC, memo, useMemo } from "react"
import { View, ViewStyle, TextStyle, ImageStyle, Pressable } from "react-native"
import { Image } from "expo-image"

import { Text } from "@/components/Text"
import type { Content, Message as ConversationMessage } from "@/services/api/conversations"
import { useAppTheme } from "@/theme/context"
import type { ThemedStyle } from "@/theme/types"

interface MessageItemProps {
  message: ConversationMessage
  showTimestamp?: boolean
  timestamp?: Date
  style?: {
    container?: ThemedStyle<ViewStyle>
    bubble?: ThemedStyle<ViewStyle>
    text?: ThemedStyle<TextStyle>
    meta?: ThemedStyle<TextStyle>
    image?: ImageStyle
  }
  setViewingImages?: any
}

interface RenderContent {
  type: "text" | "image" | "creation" | "pending"
  text?: string
  images?: string[]
}

const extractContent = (
  content: Content,
  state?: ConversationMessage["state"],
): RenderContent | null => {
  switch (content.contentType) {
    case "text":
      return content.textBlock?.text ? { type: "text", text: content.textBlock.text } : null

    case "image":
      return content.imageBlock?.image?.url
        ? { type: "image", images: [content.imageBlock.image.url] }
        : null

    case "creation":
      if (!content.creationBlock?.creations?.length) return null
      const urls = content.creationBlock.creations.flatMap((creation) => {
        const preview = creation.image?.imagePreview?.url
        const origin = creation.image?.imageOrigin?.url
        const resolved = [origin].filter((url): url is string => Boolean(url))
        return resolved
      })
      if (urls.length) {
        return state === "pending"
          ? { type: "pending", images: urls }
          : { type: "creation", images: urls }
      }
      return state === "pending" ? { type: "pending", images: [] } : null

    default:
      return null
  }
}

const getRoleFromDirection = (
  direction?: ConversationMessage["direction"],
): "user" | "assistant" => {
  if (direction === "ask") return "user"
  return "assistant"
}

const MessageBubble: FC<{
  role: "user" | "assistant"
  contents: RenderContent[]
  style?: MessageItemProps["style"]
  setViewingImages?: any
}> = ({ role, contents, style, setViewingImages }) => {
  const { themed } = useAppTheme()
  const hasOnlyNonText = contents.every((item) => item.type !== "text")

  return (
    <View style={themed(style?.bubble || $defaultMessageBubble(role, hasOnlyNonText))}>
      {contents.map((item, index) => {
        if (item.type === "pending") {
          return (
            <View key={`pending-${index}`} style={themed($pendingCard)}>
              <Text style={themed($pendingText)}>图片生成中...</Text>
            </View>
          )
        }

        if (item.type === "text" && item.text) {
          return (
            <Text key={`text-${index}`} style={themed(style?.text || $defaultMessageText(role))}>
              {item.text}
            </Text>
          )
        }

        const images = item.images ?? []
        if (!images.length) return null

        return (
          <View key={`images-${index}`} style={themed($imageGrid)}>
            {images.map((uri, imageIndex) => (
              <Pressable
                key={`${uri}-${imageIndex}`}
                onPress={() => {
                  setViewingImages({ images, index: imageIndex, visible: true })
                }}
              >
                <Image source={{ uri }} style={style?.image ?? $imageThumb} />
              </Pressable>
            ))}
          </View>
        )
      })}
    </View>
  )
}

export const MessageItem: FC<MessageItemProps> = memo(
  ({ message, showTimestamp = true, timestamp, style, setViewingImages }) => {
    const { themed } = useAppTheme()
    const role = getRoleFromDirection(message.direction)

    console.log("message", message)
    const resolvedContents = useMemo(() => {
      return (message.contents || [])
        .map((content) => extractContent(content, message.state))
        .filter(Boolean) as RenderContent[]
    }, [message.contents, message.state])

    const resolvedTimestamp = timestamp ?? new Date()

    return (
      <View style={themed(style?.container || $defaultMessageContainer(role))}>
        <MessageBubble
          role={role}
          contents={resolvedContents}
          style={style}
          setViewingImages={setViewingImages}
        />

        {showTimestamp ? (
          <Text style={themed(style?.meta || $defaultMessageMeta)}>
            {resolvedTimestamp.toLocaleTimeString()}
          </Text>
        ) : null}
      </View>
    )
  },
)

MessageItem.displayName = "MessageItem"

const $defaultMessageContainer =
  (role: "user" | "assistant"): ThemedStyle<ViewStyle> =>
  ({ spacing }) => ({
    marginBottom: spacing.sm,
    alignItems: role === "user" ? "flex-end" : "flex-start",
  })

const $defaultMessageBubble =
  (role: "user" | "assistant", compact: boolean): ThemedStyle<ViewStyle> =>
  ({ colors, spacing }) => ({
    maxWidth: "80%",
    paddingHorizontal: compact ? spacing.sm : spacing.md,
    paddingVertical: compact ? spacing.sm : spacing.md,
    borderRadius: 16,
    backgroundColor: role === "user" ? colors.palette.neutral300 : colors.palette.neutral200,
    borderBottomRightRadius: role === "user" ? 4 : 16,
    borderBottomLeftRadius: role === "user" ? 16 : 4,
    gap: spacing.xs,
  })

const $defaultMessageText =
  (role: "user" | "assistant"): ThemedStyle<TextStyle> =>
  ({ colors }) => ({
    color: colors.text,
    fontSize: 16,
    lineHeight: 22,
  })

const $defaultMessageMeta: ThemedStyle<TextStyle> = ({ colors, spacing }) => ({
  color: colors.textDim,
  fontSize: 12,
  marginTop: spacing.xs,
  textAlign: "center",
})

const $imageGrid: ThemedStyle<ViewStyle> = ({ spacing }) => ({
  flexDirection: "row",
  flexWrap: "wrap",
  gap: spacing.xs,
})

const $imageThumb: ImageStyle = {
  width: 120,
  height: 120,
  borderRadius: 12,
}

const $pendingCard: ThemedStyle<ViewStyle> = ({ colors, spacing }) => ({
  width: 120,
  height: 120,
  borderRadius: 12,
  borderWidth: 1,
  borderStyle: "dashed",
  borderColor: colors.palette.neutral400,
  justifyContent: "center",
  alignItems: "center",
  backgroundColor: colors.palette.neutral100,
  padding: spacing.sm,
})

const $pendingText: ThemedStyle<TextStyle> = ({ colors }) => ({
  color: colors.textDim,
  fontSize: 12,
  textAlign: "center",
})

export type { MessageItemProps }
